package de.fmannan.addbook.persistence.xmlwriter;

import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStream;
import java.io.IOException;
import java.util.Stack;

import org.apache.log4j.Logger;


/**
 * @author fmannan 
 * 
 * A small tool which writes XML to file.
 */
public class XMLWriter 
{
	private static final Logger log = Logger.getLogger(XMLWriter.class);
	
    private Writer writer;
    private Stack names = new Stack();
    private boolean inStartTag;

    private static final String LT = "&lt;";
    private static final String GT = "&gt;";
    private static final String AMP = "&amp;";
    private static final String APOS = "&apos;";
    private static final String QUOT = "&quot;";
    
    public XMLWriter(Writer writer)
    {
    	log.debug("Creating new XMLWriter");
        this.writer = writer;
    }

    public XMLWriter(OutputStream stm, String charsetName) throws UnsupportedEncodingException
    {
    	log.debug("Creating new XMLWriter");
		this.writer = new BufferedWriter(new OutputStreamWriter(stm, charsetName));
    }

    private void writeEscaped(char c) throws IOException
    {
        switch(c)
        {
        case '<':
            write(LT);
            break;
        case '>':
            write(GT);
            break;
        case '&':
            write(AMP);
            break;
        case '\'':
            write(APOS);
            break;
        case '"':
            write(QUOT);
            break;
        default:
            write(c);
        }
    }
    
    private void writeEscaped(String str) throws IOException
    {
        for (int i = 0; i < str.length(); i++)
        {
            writeEscaped(str.charAt(i));
        }
    }

    private void write(char c) throws IOException
    {
        writer.write(c);
    }
    
    private void write(String str) throws IOException
    {
        writer.write(str);
    }
    
    public void writeStartElement(String name) throws IOException
    {
        if (inStartTag)
        {
            write(">");
            inStartTag = false;
        }
        
        names.push(name);
        
        write("<");
        write(name);
        inStartTag = true;
    }
    
    public void writeEndElement() throws IOException
    {
        String name = (String)names.pop();
        
        if (inStartTag)
        {
            write("/>");
        }
        else
        {
            write("</");
            write(name);
            write(">");
        }
        
        inStartTag = false;
    }
    
    public void writeAttribute(String name, String value) throws IOException
    {
        if (!inStartTag)
        {
            throw new IllegalStateException("Unexpected");
        }
        
        write(" ");
        write(name);
        write("=\"");
        writeEscaped(value);
        write("\"");
    }

    public void writeAttribute(String name, int value) throws IOException
    {
        writeAttribute(name, String.valueOf(value));
    }
    
    public void writeText(String value) throws IOException
    {
        if (inStartTag)
        {
            write(">");
            inStartTag = false;
        }
        
        write(value);
    }
    
    public void writeComment(String openingTag, String endTag, String comment) throws IOException {
    	write(openingTag);
    	write(comment);
    	write(endTag);
    }
    
    /**
	 * Writes the given encoding of the XML file.
	 * 
	 * @param encoding
	 *            the tag is build from the version and the encoding passed to
	 *            the method
	 */
    public void writeEncoding (String version, String encoding) throws IOException{
    	write("<?xml version=\"");
    	write(version);
    	write("\" encoding=\"");
    	write(encoding);
    	write("\"?>");
    }
    
    public void flush() throws IOException
    {
        writer.flush();
    }
    
    public void close() throws IOException
    {
        writer.close();
    }
}

